/*

    Track reader for "Dell Axim Navigation System" GPB files,

    Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA

 */
 
#include "defs.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#define MYNAME "axim_gpb"

#define RECORD_LEN	344

static gbfile *fin;

static
arglist_t axim_gpb_args[] = {
	ARG_TERMINATOR
};

static float
le_read32_float(const void *src)
{
	float f;
	gbint32 i;
	
	i = le_read32(src);
	memcpy(&f, &i, 4);
	
	return f;
}

static void
decode_buff(const char *buff, route_head *track)
{
	struct tm tm;
	double lat, lon, alt, dir;
	float vdop, hdop, pdop, spd, Uf1;
	int sats;
	waypoint *wpt;
	
	wpt = waypt_new();
	
	memset(&tm, '\0', sizeof(tm));
	
	tm.tm_year = le_read16((void *) (buff + 16));
	tm.tm_mon = le_read16((void *)  (buff + 18));
	tm.tm_mday = le_read16((void *) (buff + 22));
	tm.tm_hour = le_read16((void *) (buff + 24));
	tm.tm_min = le_read16((void *)  (buff + 26));
	tm.tm_sec = le_read16((void *)  (buff + 28));
	lat = le_read_double( (void *)  (buff + 32));
	lon = le_read_double( (void *)  (buff + 40));	
	spd = le_read32_float((void *)  (buff + 48));
	dir = le_read32_float((void *)  (buff + 52));

	alt = le_read32_float((void *)  (buff + 64));
	Uf1 = le_read32_float((void *)  (buff + 68));

	hdop = le_read32_float((void *) (buff + 84));
	vdop = le_read32_float((void *) (buff + 88));
	pdop = le_read32_float((void *) (buff + 92));
	sats = le_read16((void *)       (buff + 96));

	wpt->latitude = lat;
	wpt->longitude = lon;
	wpt->altitude = alt;
#if 0
	/* These values can be, but must not be right. */
	/* Further checks are needed to verify that. */
	/*         (!!! reference data !!!)          */
	WAYPT_SET(wpt, course, dir);
	wpt->hdop = hdop;
	wpt->vdop = vdop;
	wpt->pdop = pdop;
	wpt->sat = sats;
	WAYPT_SET(wpt, speed, spd * 10);
#endif
	/* We don't have a header with some magic fixed numbers or strings. */
	/* So let us check the range for some basic values */
	
	is_fatal(
		(tm.tm_year < 2005) || 
		(tm.tm_mon < 1) || (tm.tm_mon > 12) || 
		(tm.tm_mday < 1) || (tm.tm_mday > 31) ||
		(tm.tm_hour > 23) || (tm.tm_min > 60) || (tm.tm_sec > 60),
		MYNAME ": Invalid or unsupported file (invalid time-stamp).");
	is_fatal(
		(fabs(wpt->latitude) > 90) ||
		(fabs(wpt->longitude) > 180),
		MYNAME ": Invalid or unsupported file (lat or/and lon out of range).");

	/* post work */
	
	tm.tm_year-=1900;
	tm.tm_mon--;
	wpt->creation_time = mkgmtime(&tm);

	track_add_wpt(track, wpt);
}

/*******************************************************************************
* %%%        global callbacks called by gpsbabel main process              %%% *
*******************************************************************************/

static void
axim_gpb_rd_init(const char *fname)
{
	fin = gbfopen(fname, "rb", MYNAME);
}

static void 
axim_gpb_rd_deinit(void)
{
	gbfclose(fin);
}

static void
axim_gpb_read(void)
{
	char buff[RECORD_LEN];
	route_head *track = NULL;
	size_t bytes;

	while ((bytes = gbfread(buff, 1, RECORD_LEN, fin)))
	{
		is_fatal((bytes != RECORD_LEN), MYNAME ": Invalid or unsupported file (filesize).");
		if (track == NULL)
		{
			track = route_head_alloc();
			track_add_head(track);
		}
		decode_buff(buff, track);
	}
}

/**************************************************************************/

ff_vecs_t axim_gpb_vecs = {
	ff_type_file,
	{ 
		ff_cap_none 	/* waypoints */, 
		ff_cap_read 	/* tracks */, 
	  	ff_cap_none 	/* routes */, 
	},
	axim_gpb_rd_init,	
	NULL,	
	axim_gpb_rd_deinit,	
	NULL,	
	axim_gpb_read,
	NULL,
	NULL,
	axim_gpb_args,
	CET_CHARSET_ASCII, 0
};
/**************************************************************************/
